########################################################################
# $HeadURL: http://dirac-grid.googlecode.com/svn/BelleDIRAC/trunk/BelleDIRAC/DataManagementSystem/DB/IntegratedFCDB.py $
########################################################################
""" IntegratedFC class is a front-end to the Belle II Metadata Database
"""
__RCSID__ = "$Id: IntegratedFCDB.py 222 2010-07-29 09:42:06Z ricardo.graciani $"


import time
import random
from DIRAC  import gConfig, gLogger, S_OK, S_ERROR
from DIRAC.Core.Base.DB import DB
from DIRAC.Core.Security.X509Request import X509Request
from DIRAC.Core.Security.X509Chain import X509Chain
from DIRAC.Core.Security.MyProxy import MyProxy
from DIRAC.Core.Security.VOMS import VOMS
from DIRAC.Core.Security import CS

from BelleDIRAC.DataManagementSystem.DB.IntegratedFCComponents.IntegratedCatalog   import IntegratedCatalog
from BelleDIRAC.DataManagementSystem.DB.IntegratedFCComponents.Utilities import *


class IntegratedFCDB( DB ):

  def __init__( self, maxQueueSize = 10 ):
    DB.__init__( self, 'IntegratedFCDB', 'DataManagement/IntegratedFCDB', maxQueueSize )
    retVal = self.__initializeDB()
    if not retVal[ 'OK' ]:
      raise Exception( "Can't create tables: %s" % retVal[ 'Message' ] )

  def __initializeDB( self ):
    """
    Create the tables
    """
    retVal = self._query( "show tables" )
    if not retVal[ 'OK' ]:
      return retVal

    tablesInDB = [ t[0] for t in retVal[ 'Value' ] ]
    tablesD = {}
    """
       tableName: { 'Fields' : { 'Field': 'Description' },
                    'ForeignKeys': {'Field': 'Table.key' },
                    'PrimaryKey': 'Id',
                    'Indexes': { 'Index': [] },
                    'UniqueIndexes': { 'Index': [] },
                    'Engine': 'InnoDB' }

    """

    if 'IntegratedFCDB_Tree' not in tablesInDB:
      tablesD[ 'IntegratedFCDB_Tree' ] = { 'Fields' : { 'EntryId' : 'INTEGER UNSIGNED NOT NULL AUTO_INCREMENT',
                                                        'ParentId' : 'INTEGER UNSIGNED NOT NULL',
                                                        'NameId' : 'INTEGER UNSIGNED NOT NULL',
                                                        'Type' : 'INTEGER UNSIGNED NOT NULL',
                                                        'OwnerId' : 'INTEGER UNSIGNED NOT NULL',
                                                        'ACL' : 'BIT(4)',
                                                        'Date' : 'DATETIME NOT NULL'
                                                        },
                                           'PrimaryKey' : 'EntryId',
                                           'UniqueIndexes' : { 'UniqueEntry': ['ParentId', 'NameId'] },
                                           'ForeignKeys': { 'NameId' : 'IntegratedFCDB_Names',
                                                            'OwnerId' : 'IntegratedFCDB_Owners'
                                                            },
                                           }

    if 'IntegratedFCDB_Files' not in tablesInDB:
      tablesD[ 'IntegratedFCDB_Files' ] = { 'Fields' : { 'FileId' : 'INTEGER UNSIGNED NOT NULL',
                                                         'Size' : 'BIGINT UNSIGNED NOT NULL',
                                                         'GUID' : 'INTEGER UNSIGNED NOT NULL',
                                                         'adler32' : 'INTEGER UNSIGNED',
                                                         'md5' : 'INTEGER UNSIGNED',
                                                         'Status' : 'CHAR(8) NOT NULL',
                                                         'Events' : 'INTEGER UNSIGNED NOT NULL'
                                                         },
                                            'PrimaryKey' : 'FileId',
                                            'ForeignKeys': { 'FileId': 'IntegratedFCDB_Tree.EntryId' },
                                            }
    if 'IntegratedFCDB_Links' not in tablesInDB:
      tablesD[ 'IntegratedFCDB_Links' ] = { 'Fields' : { 'SourceId' : 'INTEGER UNSIGNED NOT NULL',
                                                         'DestinationId' : 'INTEGER UNSIGNED NOT NULL'
                                                         },
                                            'PrimaryKey' : 'SourceId',
                                            'ForeignKeys' : { 'SourceId' : 'IntegratedFCDB_Tree.EntryId',
                                                              'DestinationId' : 'IntegratedFCDB_Files.FileId'
                                                              },
                                            }
    if 'IntegratedFCDB_SEs' not in tablesInDB:
      tablesD[ 'IntegratedFCDB_SEs' ] = { 'Fields' : { 'SEId' : 'INTEGER UNSIGNED NOT NULL AUTO_INCREMENT',
                                                       'SE' : 'VARCHAR(256) NOT NULL'
                                                       },
                                          'PrimaryKey' : 'SEId',
                                          }
    if 'IntegratedFCDB_Categories' not in tablesInDB:
      tablesD[ 'IntegratedFCDB_Categories' ] = { 'Fields' : { 'CategoryId' : 'INTEGER UNSIGNED NOT NULL AUTO_INCREMENT',
                                                              'Category' : 'VARCHAR(512) NOT NULL',
                                                              'Type' : 'TINYINT(4)'
                                                              },
                                                 'PrimaryKey' : 'CategoryId',
                                                 'UniqueIndexes' : { 'Category': ['Category'] },
                                                 }
    if 'IntegratedFCDB_Values' not in tablesInDB:
      tablesD[ 'IntegratedFCDB_Values' ] = { 'Fields' : { 'ValueId' : 'INTEGER UNSIGNED NOT NULL AUTO_INCREMENT',
                                                          'CategoryId' : 'INTEGER UNSIGNED NOT NULL',
                                                          'Value' : 'VARCHAR(512)'
                                                          },
                                             'PrimaryKey' : 'ValueId',
                                             'ForeignKeys' : { 'CategoryId' : 'IntegratedFCDB_Categories' },
                                             }
    if 'IntegratedFCDB_Replicas' not in tablesInDB:
      tablesD[ 'IntegratedFCDB_Replicas' ] = { 'Fields' : { 'FileId' : 'INTEGER UNSIGNED NOT NULL',
                                                            'SEId' : 'INTEGER UNSIGNED NOT NULL'
                                                            },
                                               'UniqueIndexes' : { 'Replica': ['SEId', 'FileId'] },
                                               'ForeignKeys' : { 'FileId' : 'IntegratedFCDB_Files',
                                                                 'SEId' : 'IntegratedFCDB_SEs'
                                                                  },
                                               }
    if 'IntegratedFCDB_Ancestors' not in tablesInDB:
      tablesD[ 'IntegratedFCDB_Ancestors' ] = { 'Fields' : { 'FileId' : 'INTEGER UNSIGNED NOT NULL',
                                                             'AncestorId' : 'INTEGER UNSIGNED NOT NULL'
                                                             },
                                                'PrimaryKey' : 'FileId',
                                                'ForeignKeys' : { 'FileId' : 'IntegratedFCDB_Files',
                                                                  'AncestorId' : 'IntegratedFCDB_Files.FileId'
                                                                  },
                                                }
    if 'IntegratedFCDB_Names' not in tablesInDB:
      tablesD[ 'IntegratedFCDB_Names' ] = { 'Fields' : { 'NameId' : 'INTEGER UNSIGNED NOT NULL AUTO_INCREMENT',
                                                         'Name' : 'VARCHAR(512) NOT NULL'
                                                         },
                                            'UniqueIndexes' : { 'Name': ['Name'] },
                                            'PrimaryKey' : 'NameId',
                                            }
    if 'IntegratedFCDB_Comments' not in tablesInDB:
      tablesD[ 'IntegratedFCDB_Comments' ] = { 'Fields' : { 'EntryId' : 'INTEGER UNSIGNED NOT NULL',
                                                            'Comment' : 'VARCHAR(4096) NOT NULL'
                                                   },
                                        'PrimaryKey' : 'EntryId',
                                        'ForeignKeys' : { 'EntryId' : 'IntegratedFCDB_Tree'},
                                      }
    if 'IntegratedFCDB_Groups' not in tablesInDB:
      tablesD[ 'IntegratedFCDB_Groups' ] = { 'Fields' : { 'GroupId' : 'INTEGER UNSIGNED NOT NULL AUTO_INCREMENT',
                                                          'Group' : 'CHAR(32) NOT NULL',
                                                          },
                                             'UniqueIndexes' : { 'Group': ['Group'] },
                                             'PrimaryKey' : 'GroupId',
                                             }
    if 'IntegratedFCDB_Users' not in tablesInDB:
      tablesD[ 'IntegratedFCDB_Users' ] = { 'Fields' : { 'UserId' : 'INTEGER UNSIGNED NOT NULL AUTO_INCREMENT',
                                                         'User' : 'CHAR(32) NOT NULL'
                                                          },
                                            'UniqueIndexes' : { 'User': ['User'] },
                                            'PrimaryKey' : 'UserId',
                                            }
    if 'IntegratedFCDB_VOs' not in tablesInDB:
      tablesD[ 'IntegratedFCDB_VOs' ] = { 'Fields' : { 'VOId' : 'INTEGER UNSIGNED NOT NULL AUTO_INCREMENT',
                                                       'VO' : 'CHAR(32) NOT NULL'
                                                       },
                                          'UniqueIndexes' : { 'VO': ['VO'] },
                                          'PrimaryKey' : 'VOId',
                                          }
    if 'IntegratedFCDB_Owners' not in tablesInDB:
      tablesD[ 'IntegratedFCDB_Owners' ] = { 'Fields' : { 'OwnerId' : 'INTEGER UNSIGNED NOT NULL AUTO_INCREMENT',
                                                          'VOId' : 'INTEGER UNSIGNED NOT NULL',
                                                          'GroupId' : 'INTEGER UNSIGNED NOT NULL',
                                                          'UserId' : 'INTEGER UNSIGNED NOT NULL',
                                                          },
                                             'PrimaryKey' : 'OwnerId',
                                             'ForeignKeys' : { 'VOId' : 'IntegratedFCDB_VOs',
                                                               'GroupId': 'IntegratedFCDB_Groups',
                                                               'UserId': 'IntegratedFCDB_Users' },
                                             'UniqueIndexes' : { 'Owner': ['VOId', 'GroupId', 'UserId'] },
                                             }
    if 'IntegratedFCDB_Metadata' not in tablesInDB:
      tablesD[ 'IntegratedFCDB_Metadata' ] = { 'Fields' : { 'EntryId' : 'INTEGER UNSIGNED NOT NULL',
                                                            'ValueId' : 'INTEGER UNSIGNED NOT NULL'
                                                            },
                                               'ForeignKeys' : { 'EntryId' : 'IntegratedFCDB_Tree',
                                                                 'ValueId' : 'IntegratedFCDB_Values' },
                                               'UniqueIndexes' : { 'Metadata': ['EntryId', 'ValueId' ] },
                                               }

    return self._createTables( tablesD )

  def setConfig( self, databaseConfig ):
    # Obtain some general configuration of the database
    self.uniqueGUID = databaseConfig['UniqueGUID']
    self.globalReadAccess = databaseConfig['GlobalReadAccess']
    self.lfnPfnConvention = databaseConfig['LFNPFNConvention']
    self.resolvePfn = databaseConfig['ResolvePFN']
    self.umask = databaseConfig['DefaultUmask']

    self.ugManager = eval( "%s(self)" % databaseConfig['UserGroupManager'] )
    self.seManager = eval( "%s(self)" % databaseConfig['SEManager'] )
    self.securityManager = eval( "%s(self)" % databaseConfig['SecurityManager'] )
    self.dtree = eval( "%s(self)" % databaseConfig['DirectoryManager'] )
    self.fileManager = eval( "%s(self)" % databaseConfig['FileManager'] )
    try:
      # Obtain the plugins to be used for DB interaction
      self.ugManager = eval( "%s(self)" % databaseConfig['UserGroupManager'] )
      self.seManager = eval( "%s(self)" % databaseConfig['SEManager'] )
      self.securityManager = eval( "%s(self)" % databaseConfig['SecurityManager'] )
      self.dtree = eval( "%s(self)" % databaseConfig['DirectoryManager'] )
      self.fileManager = eval( "%s(self)" % databaseConfig['FileManager'] )
    except Exception, x:
      gLogger.fatal( "Failed to create database objects", x )
      return S_ERROR( "Failed to create database objects" )

    # In memory storage of the various parameters
    self.directories = {}
    self.users = {}
    self.uids = {}
    self.groups = {}
    self.gids = {}
    self.seDefinitions = {}
    return S_OK()

  def setUmask( self, umask ):
    self.umask = umask

  ########################################################################
  #
  #  User/groups based write methods
  #

  def addUser( self, userName, credDict ):
    res = self._checkAdminPermission( credDict )
    if not res['OK']:
      return res
    if not res['Value']:
      return S_ERROR( "Permission denied" )
    return self.ugManager.addUser( userName )

  def deleteUser( self, userName, credDict ):
    res = self._checkAdminPermission( credDict )
    if not res['OK']:
      return res
    if not res['Value']:
      return S_ERROR( "Permission denied" )
    return self.ugManager.deleteUser( userName )

  def addGroup( self, groupName, credDict ):
    res = self._checkAdminPermission( credDict )
    if not res['OK']:
      return res
    if not res['Value']:
      return S_ERROR( "Permission denied" )
    return self.ugManager.addGroup( groupName )

  def deleteGroup( self, groupName, credDict ):
    res = self._checkAdminPermission( credDict )
    if not res['OK']:
      return res
    if not res['Value']:
      return S_ERROR( "Permission denied" )
    return self.ugManager.deleteGroup( groupName )

  ########################################################################
  #
  #  User/groups based read methods
  #

  def getUsers( self, credDict ):
    res = self._checkAdminPermission( credDict )
    if not res['OK']:
      return res
    if not res['Value']:
      return S_ERROR( "Permission denied" )
    return self.ugManager.getUsers()

  def getGroups( self, credDict ):
    res = self._checkAdminPermission( credDict )
    if not res['OK']:
      return res
    if not res['Value']:
      return S_ERROR( "Permission denied" )
    return self.ugManager.getGroups()

  ########################################################################
  #
  #  Path based read methods
  #

  def exists( self, lfns, credDict ):
    res = self._checkPathPermissions( 'Read', lfns, credDict )
    if not res['OK']:
      return res
    failed = res['Value']['Failed']
    res = self.fileManager.exists( res['Value']['Successful'] )
    if not res['OK']:
      return res
    failed.update( res['Value']['Failed'] )
    successful = res['Value']['Successful']
    notExist = []
    for lfn in res['Value']['Successful'].keys():
      if not successful[lfn]:
        notExist.append( lfn )
        successful.pop( lfn )
    if notExist:
      res = self.dtree.exists( notExist )
      if not res['OK']:
        return res
      failed.update( res['Value']['Failed'] )
      successful.update( res['Value']['Successful'] )
    return S_OK( {'Successful':successful, 'Failed':failed} )

  def getPathPermissions( self, lfns, credDict ):
    """ Get permissions for the given user/group to manipulate the given lfns 
    """
    res = self._checkPathPermissions( 'Read', lfns, credDict )
    if not res['OK']:
      return res
    failed = res['Value']['Failed']
    res = self.dtree.getPathPermissions( res['Value']['Successful'], credDict )
    if not res['OK']:
      return res
    failed.update( res['Value']['Failed'] )
    successful = res['Value']['Successful']
    return S_OK( {'Successful':successful, 'Failed':failed} )

  ########################################################################
  #
  #  Path based read methods
  #

  def changePathOwner( self, lfns, credDict, recursive = False ):
    """ Change the owner of the given list of paths
    """
    res = self._checkPathPermissions( 'Write', lfns, credDict )
    if not res['OK']:
      return res
    failed = res['Value']['Failed']
    res = self.fileManager.changePathOwner( res['Value']['Successful'], credDict, recursive )
    if not res['OK']:
      return res
    failed.update( res['Value']['Failed'] )
    successful = res['Value']['Successful']
    return S_OK( {'Successful':successful, 'Failed':failed} )

  def changePathGroup( self, lfns, credDict, recursive = False ):
    """ Change the group of the given list of paths
    """
    res = self._checkPathPermissions( 'Write', lfns, credDict )
    if not res['OK']:
      return res
    failed = res['Value']['Failed']
    res = self.fileManager.changePathGroup( res['Value']['Successful'], credDict, recursive )
    if not res['OK']:
      return res
    failed.update( res['Value']['Failed'] )
    successful = res['Value']['Successful']
    return S_OK( {'Successful':successful, 'Failed':failed} )

  def changePathMode( self, lfns, credDict, recursive = False ):
    """ Change the mode of the given list of paths
    """
    res = self._checkPathPermissions( 'Write', lfns, credDict )
    if not res['OK']:
      return res
    failed = res['Value']['Failed']
    res = self.fileManager.changePathMode( res['Value']['Successful'], credDict, recursive )
    if not res['OK']:
      return res
    failed.update( res['Value']['Failed'] )
    successful = res['Value']['Successful']
    return S_OK( {'Successful':successful, 'Failed':failed} )

  ########################################################################
  #
  #  File based write methods
  #

  def addFile( self, lfns, credDict ):
    res = self._checkPathPermissions( 'Write', lfns, credDict )
    if not res['OK']:
      return res
    failed = res['Value']['Failed']
    res = self.fileManager.addFile( res['Value']['Successful'], credDict )
    if not res['OK']:
      return res
    failed.update( res['Value']['Failed'] )
    successful = res['Value']['Successful']
    return S_OK( {'Successful':successful, 'Failed':failed} )

  def removeFile( self, lfns, credDict ):
    res = self._checkPathPermissions( 'Write', lfns, credDict )
    if not res['OK']:
      return res
    failed = res['Value']['Failed']
    res = self.fileManager.removeFile( res['Value']['Successful'] )
    if not res['OK']:
      return res
    failed.update( res['Value']['Failed'] )
    successful = res['Value']['Successful']
    return S_OK( {'Successful':successful, 'Failed':failed} )

  def addReplica( self, lfns, credDict ):
    res = self._checkPathPermissions( 'Write', lfns, credDict )
    if not res['OK']:
      return res
    failed = res['Value']['Failed']
    res = self.fileManager.addReplica( res['Value']['Successful'] )
    if not res['OK']:
      return res
    failed.update( res['Value']['Failed'] )
    successful = res['Value']['Successful']
    return S_OK( {'Successful':successful, 'Failed':failed} )

  def removeReplica( self, lfns, credDict ):
    res = self._checkPathPermissions( 'Write', lfns, credDict )
    if not res['OK']:
      return res
    failed = res['Value']['Failed']
    res = self.fileManager.removeReplica( res['Value']['Successful'] )
    if not res['OK']:
      return res
    failed.update( res['Value']['Failed'] )
    successful = res['Value']['Successful']
    return S_OK( {'Successful':successful, 'Failed':failed} )

  def setReplicaStatus( self, lfns, credDict ):
    res = self._checkPathPermissions( 'Write', lfns, credDict )
    if not res['OK']:
      return res
    failed = res['Value']['Failed']
    res = self.fileManager.setReplicaStatus( res['Value']['Successful'] )
    if not res['OK']:
      return res
    failed.update( res['Value']['Failed'] )
    successful = res['Value']['Successful']
    return S_OK( {'Successful':successful, 'Failed':failed} )

  def setReplicaHost( self, lfns, credDict ):
    res = self._checkPathPermissions( 'Write', lfns, credDict )
    if not res['OK']:
      return res
    failed = res['Value']['Failed']
    res = self.fileManager.setReplicaHost( res['Value']['Successful'] )
    if not res['OK']:
      return res
    failed.update( res['Value']['Failed'] )
    successful = res['Value']['Successful']
    return S_OK( {'Successful':successful, 'Failed':failed} )

  ########################################################################
  #
  #  File based read methods
  #

  def isFile( self, lfns, credDict ):
    res = self._checkPathPermissions( 'Read', lfns, credDict )
    if not res['OK']:
      return res
    failed = res['Value']['Failed']
    res = self.fileManager.isFile( res['Value']['Successful'] )
    if not res['OK']:
      return res
    failed.update( res['Value']['Failed'] )
    successful = res['Value']['Successful']
    return S_OK( {'Successful':successful, 'Failed':failed} )

  def getFileSize( self, lfns, credDict ):
    res = self._checkPathPermissions( 'Read', lfns, credDict )
    if not res['OK']:
      return res
    failed = res['Value']['Failed']
    res = self.fileManager.getFileSize( res['Value']['Successful'] )
    if not res['OK']:
      return res
    failed.update( res['Value']['Failed'] )
    successful = res['Value']['Successful']
    return S_OK( {'Successful':successful, 'Failed':failed} )

  def getFileMetadata( self, lfns, credDict ):
    res = self._checkPathPermissions( 'Read', lfns, credDict )
    if not res['OK']:
      return res
    failed = res['Value']['Failed']
    res = self.fileManager.getFileMetadata( res['Value']['Successful'] )
    if not res['OK']:
      return res
    failed.update( res['Value']['Failed'] )
    successful = res['Value']['Successful']
    return S_OK( {'Successful':successful, 'Failed':failed} )

  def getReplicas( self, lfns, allStatus, credDict ):
    res = self._checkPathPermissions( 'Read', lfns, credDict )
    if not res['OK']:
      return res
    failed = res['Value']['Failed']
    res = self.fileManager.getReplicas( res['Value']['Successful'], allStatus = allStatus )
    if not res['OK']:
      return res
    failed.update( res['Value']['Failed'] )
    successful = res['Value']['Successful']
    return S_OK( {'Successful':successful, 'Failed':failed} )

  def getReplicaStatus( self, lfns, credDict ):
    res = self._checkPathPermissions( 'Read', lfns, credDict )
    if not res['OK']:
      return res
    failed = res['Value']['Failed']
    res = self.fileManager.getReplicaStatus( res['Value']['Successful'] )
    if not res['OK']:
      return res
    failed.update( res['Value']['Failed'] )
    successful = res['Value']['Successful']
    return S_OK( {'Successful':successful, 'Failed':failed} )

  ########################################################################
  #
  #  Directory based Write methods
  #

  def createDirectory( self, lfns, credDict ):
    res = self._checkPathPermissions( 'Write', lfns, credDict )
    if not res['OK']:
      return res
    failed = res['Value']['Failed']
    res = self.dtree.createDirectory( res['Value']['Successful'], credDict )
    if not res['OK']:
      return res
    failed.update( res['Value']['Failed'] )
    successful = res['Value']['Successful']
    return S_OK( {'Successful':successful, 'Failed':failed} )

  def removeDirectory( self, lfns, credDict ):
    res = self._checkPathPermissions( 'Write', lfns, credDict )
    if not res['OK']:
      return res
    failed = res['Value']['Failed']
    res = self.dtree.removeDirectory( res['Value']['Successful'], credDict )
    if not res['OK']:
      return res
    failed.update( res['Value']['Failed'] )
    successful = res['Value']['Successful']
    return S_OK( {'Successful':successful, 'Failed':failed} )

  ########################################################################
  #
  #  Directory based read methods
  #

  def listDirectory( self, lfns, credDict, verbose = False ):
    res = self._checkPathPermissions( 'Read', lfns, credDict )
    if not res['OK']:
      return res
    failed = res['Value']['Failed']
    res = self.dtree.listDirectory( res['Value']['Successful'], verbose = verbose )
    if not res['OK']:
      return res
    failed.update( res['Value']['Failed'] )
    successful = res['Value']['Successful']
    return S_OK( {'Successful':successful, 'Failed':failed} )

  def isDirectory( self, lfns, credDict ):
    res = self._checkPathPermissions( 'Read', lfns, credDict )
    if not res['OK']:
      return res
    failed = res['Value']['Failed']
    res = self.dtree.isDirectory( res['Value']['Successful'] )
    if not res['OK']:
      return res
    failed.update( res['Value']['Failed'] )
    successful = res['Value']['Successful']
    return S_OK( {'Successful':successful, 'Failed':failed} )

  def getDirectoryReplicas( self, lfns, allStatus, credDict ):
    res = self._checkPathPermissions( 'Read', lfns, credDict )
    if not res['OK']:
      return res
    failed = res['Value']['Failed']
    res = self.dtree.getDirectoryReplicas( res['Value']['Successful'] )
    if not res['OK']:
      return res
    failed.update( res['Value']['Failed'] )
    successful = res['Value']['Successful']
    return S_OK( {'Successful':successful, 'Failed':failed} )

  def getDirectorySize( self, lfns, credDict ):
    res = self._checkPathPermissions( 'Read', lfns, credDict )
    if not res['OK']:
      return res
    failed = res['Value']['Failed']
    res = self.dtree.getDirectorySize( res['Value']['Successful'] )
    if not res['OK']:
      return res
    failed.update( res['Value']['Failed'] )
    successful = res['Value']['Successful']
    return S_OK( {'Successful':successful, 'Failed':failed} )

  #######################################################################
  #
  #  Catalog admin methods
  #
  def getCatalogContents( self, credDict ):
    res = self._checkAdminPermission( credDict )
    if not res['OK']:
      return res
    if not res['Value']:
      return S_ERROR( "Permission denied" )
    res = self.dtree.getDirectoryCounters()
    if not res['OK']:
      return res
    counterDict = res['Value']
    res = self.fileManager.getFileCounters()
    if not res['OK']:
      return res
    counterDict.update( res['Value'] )
    res = self.fileManager.getReplicaCounters()
    if not res['OK']:
      return res
    counterDict.update( res['Value'] )
    return S_OK( counterDict )

  ########################################################################
  #
  #  Security based methods
  #

  def _checkAdminPermission( self, credDict ):
    return self.securityManager.hasAdminAccess( credDict )

  def _checkPathPermissions( self, operation, lfns, credDict ):
    res = checkArgumentDict( lfns )
    if not res['OK']:
      return res
    lfns = res['Value']
    res = self.securityManager.hasAccess( operation, lfns.keys(), credDict )
    if not res['OK']:
      return res
    # Do not consider those paths for which we failed to determine access
    failed = res['Value']['Failed']
    for lfn in failed.keys():
      lfns.pop( lfn )
    # Do not consider those paths for which access is denied
    for lfn, access in res['Value']['Successful'].items():
      if not access:
        failed[lfn] = 'Permission denied'
        lfns.pop( lfn )
    return S_OK( {'Successful':lfns, 'Failed':failed} )
